package org.yourscrum.domain;

import java.util.List;

public abstract class Position<T> {

    public static <T> Position<T> onTop() {
        return new FixedPosition<T>(0);
    }

    public static <T> Position<T> onBottom() {
        return new LastPosition<T>();
    }

    public static <T> Position<T> before(T otherObject) {
        return new RelativePosition<T>(otherObject, true);
    }

    public static <T> Position<T> after(T otherObject) {
        return new RelativePosition<T>(otherObject, false);
    }

    public abstract int absolutePositionInList(List<T> list);

    private static class FixedPosition<T> extends Position<T> {
        private final int index;

        public FixedPosition(final int i) {
            this.index = i;
        }

        public int absolutePositionInList(final List<T> list) {
            return index;
        }
    }

    private static class LastPosition<T> extends Position<T> {
        public int absolutePositionInList(final List<T> list) {
            return list.size();
        }
    }

    private static class RelativePosition<T> extends Position<T> {
        private T reference;
        private int relativePosition = 0;

        public RelativePosition(final T otherObject, final boolean before) {
            this.reference = otherObject;
            if (!before) {
                relativePosition = 1;
            }
        }

        public int absolutePositionInList(final List<T> list) {
            return list.indexOf(reference) + relativePosition;
        }
    }
}
